// AttributeSet.h
#pragma once
#pragma warning( push )
#pragma warning( disable : 4368 )


#include "dmalgointerfaces.h"

using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::InteropServices;
using namespace System::Collections;


#include "DMEnumerationWrappers.h"
#include "DMCaseIterHelper.h"

namespace Microsoft
{
namespace SqlServer
{
namespace DataMining
{
namespace PluginAlgorithms
{

    ref class AttributeSet;
	ref class AttributeGroup;
	ref class StateValue;
	ref class StateStatistics;
	ref class StateStatisticsCollection;
	ref class AttributeStatistics;
//	public __sealed


	   
    public   ref class AttributeGroup sealed 
	{
	private:
		IDMAttributeGroup*						m_wpAttrGroup;
		
		System::Collections::ArrayList	^	m_mrgAttrs;
		int										m_nIndex;
    internal:
        AttributeGroup(IDMAttributeGroup*   in_pAttrGroup)
        {
            m_wpAttrGroup = in_pAttrGroup;
			m_mrgAttrs	=	nullptr;
			if( m_wpAttrGroup )
			{
				m_wpAttrGroup->Reset();
			}

		}
        AttributeGroup(System::Collections::ArrayList	^	mrgOutputAttributes)
        {
            m_wpAttrGroup = NULL;
			m_mrgAttrs	=	mrgOutputAttributes;
			m_nIndex	=	-1;

		}

	public:
		bool	Next([Out]System::UInt32% attribute )
		{
			DM_Attribute	nAtt	= DM_UNSPECIFIED;
			bool			bRet	= false;

			if( m_wpAttrGroup )
			{
				USES_ERROR_HANDLING;
				THROW_ON_FAILURE( m_wpAttrGroup->Next(&nAtt) );
				if( CURRENT_STATUS ==S_OK )
				{
					attribute	=	nAtt;
					bRet		=	true;
				}
			}
			else
			{
				m_nIndex ++;
				if( m_nIndex < m_mrgAttrs->Count )
				{
					Object ^ val	=	m_mrgAttrs[m_nIndex];
					attribute =	*dynamic_cast<System::UInt32^>(val);
					bRet	=	true;
				}
			}
			return bRet;
		}

		void	Reset()
		{
			if( m_wpAttrGroup )
			{
				USES_ERROR_HANDLING;
				THROW_ON_FAILURE( m_wpAttrGroup->Reset() );
			}
			else
			{
				m_nIndex	=	-1;
			}
		}

	};

   
    public   ref class AttributeSet sealed 
    {
    private:
        IDMAttributeSet*    m_wpAttrSet;
		bool				m_fLimitedForValidation;

		void FailIfValidating()
		{
			// todo: bogdanc -- Localize
			if( m_fLimitedForValidation )
				throw gcnew System::InvalidOperationException();
		}
    internal:
        AttributeSet(IDMAttributeSet*   in_pAttrSet)
        {
            m_wpAttrSet = in_pAttrSet;
			m_fLimitedForValidation = false;
        }
    
		void	LimitForValidation()
		{
			m_fLimitedForValidation = true;
		}
    public:
		[System::Diagnostics::CodeAnalysis::SuppressMessage("Microsoft.Usage", "CA2211:NonConstantFieldsShouldNotBeVisible")]
		const static System::UInt32	Unspecified	=	DM_UNSPECIFIED;
        
	    /// <summary>
	    /// returns the flags of the specified attribute
	    /// </summary>
        AttributeFlags      GetAttributeFlags( System::UInt32   attribute);

	    /// <summary>
	    /// returns the modeling flags of the specified attribute
	    /// </summary>
        array<MiningModelingFlag>^  GetModelingFlags( System::UInt32   attribute);

	    /// <summary>
	    /// returns the underlying type of an attribute
	    /// </summary>
        System::Type ^  GetAttributeType( System::UInt32   attribute);

	    /// <summary>
	    /// returns the number of attributes
	    /// </summary>
        System::UInt32 GetAttributeCount( );

	    /// <summary>
	    /// returns the number of states of the specified attribute
	    /// </summary>
        System::UInt32 GetAttributeStateCount( System::UInt32 attribute);

	    /// <summary>
	    /// returns the display name of the specified attribute
	    /// </summary>
        String ^    GetAttributeDisplayName( System::UInt32 attribute, bool shortName);

	    /*
        // TODO: bogdanc -- See what to do about this
        /// <summary>
	    /// renders the XML for the display name of the specified attribute
	    /// </summary>
        String __gc*    GetAttributeDisplayNameXML( System::UInt32 attribute );
        */

	    /// <summary>
	    /// returns the display namke of the specified attribute
	    /// </summary>
        String ^    GetFullyQualifiedColumnName( System::UInt32 attribute);

	    
        
        /// <summary>
	    ///	Takes as argument the tokenized value and 
		/// returns the original value
		/// returns the attribute value
	    /// </summary>
        [System::Diagnostics::CodeAnalysis::SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")]
		Object^			UntokenizeAttributeValue( System::UInt32 attribute, StateValue^   tokenizedValue);
        

        /// <summary>
	    /// 
	    /// </summary>
        StateValue    ^  TokenizeAttributeValue( System::UInt32 attribute, Object ^    value);


        /*
        // TODO: bogdanc -- See what to do about this --  ambiguous behavior of the statevaluie parameter
        // and can be replaced by GetAttributeStateValue
        /// <summary>
	    /// returns the attribute value
	    /// </summary>
        void    GetInterpretedAttributeValue( System::UInt32 attribute, Object __gc*& statevalue);
        */
        
        void    GetDiscretizedStateRange( 
            System::UInt32  attribute,
            System::UInt32  stateIndex,
            bool            actual,
            System::Double% lower,
            System::Double% upper);
        
        void    GetDiscretizedStateRange( 
            System::UInt32  attribute,
            System::UInt32  stateIndex,
            bool            actual,
            System::DateTime% lower,
            System::DateTime% upper);

        bool    IsFunctionallyDependant( 
            System::UInt32  attr1,
            System::UInt32  attr2);
        
        bool    IsCaseAttribute( 
            System::UInt32  attribute);
        
        System::String ^ GetCaseIdName(long        caseId);


		System::UInt32		GetClassifiedAttribute(
								System::UInt32		attribute);


		AttributeGroup ^ GetAttributeGroup( 
								System::UInt32 attribute );



    };

	
	
	// Helper wrapper for DM_STATE_VALUE
	public   ref class StateValue sealed 
	{
	private:

	internal:
		DM_STATE_VALUE	m_val;	// for real state values
		StateStatistics^	stateStats;		// source state statistics, if any



		void    Set(DM_STATE_VALUE&    val) 
		{
			pin_ptr<DM_STATE_VALUE> ppVal = &m_val;
			*ppVal = val;
		}

		void    Set(StateStatistics^  stats) ;




		static bool		IsSVMissing(const DM_STATE_VALUE & val) 		{ return (val.si.iFlag == (ULONG)DM_INT_VALUE_MISSING) || (IsSVIndex(val) && (0==SVIndexVal(val))); }
		static bool		IsSVDouble(const DM_STATE_VALUE & val)  		{ return !IsSVIndex(val) && !IsSVMissing(val);	}
		static bool		IsSVIndex(const DM_STATE_VALUE & val)	  		{ return (val.si.iFlag == DM_INT_VALUE); }
		static DM_State	SVIndexVal(const DM_STATE_VALUE & val)  		{ return val.si.iState;	}
		static double	SVDoubleVal(const DM_STATE_VALUE & val) 		{ return val.r8; }
		static void		SetMissing(DM_STATE_VALUE & val)				{ val.si.iFlag = DM_INT_VALUE_MISSING; val.si.iState = 0; }
		static void		SetDouble(DM_STATE_VALUE & val, double r8)		{ val.r8 = r8;	}
		static void		SetIndex(DM_STATE_VALUE & val, DM_State index)	{ val.si.iFlag = DM_INT_VALUE; val.si.iState = index;	}

	public:
		// Constructors
		StateValue(){ SetMissing();}





		// Accessors
		property bool IsMissing
		{
			bool get()
			{ 
				pin_ptr<DM_STATE_VALUE> ppVal = &m_val; 
				return IsSVMissing(*ppVal); 
			}
		}
		
		property bool     IsDouble
		{
			bool get ()
			{ 
				pin_ptr<DM_STATE_VALUE> ppVal = &m_val;
				return IsSVDouble(*ppVal); 
			}
		}
		property bool IsIndex
		{
			bool get()
			{ 
				pin_ptr<DM_STATE_VALUE> ppVal = &m_val;
				return IsSVIndex(*ppVal); 
			}
		}
		
		property DM_State Index
		{
			DM_State	get()  		
			{ 
				pin_ptr<DM_STATE_VALUE> ppVal = &m_val;
				return SVIndexVal(*ppVal); 
			}
		}

		property double   Double
		{
			double get()
			{ 
				pin_ptr<DM_STATE_VALUE> ppVal = &m_val;
				return SVDoubleVal(*ppVal); 
			}
		}
		
		void	 SetMissing()				{ pin_ptr<DM_STATE_VALUE> ppVal = &m_val;SetMissing(*ppVal); UpdateStateStats();}
		void     SetDouble(double r8)		{ pin_ptr<DM_STATE_VALUE> ppVal = &m_val;SetDouble(*ppVal, r8);	UpdateStateStats();}
		void     SetIndex(ULONG index)	{ pin_ptr<DM_STATE_VALUE> ppVal = &m_val;SetIndex(*ppVal, index); UpdateStateStats();}


	private:

		void UpdateStateStats();
	};

	
	
	
	public  ref class StateStatistics sealed 
	{

	private:
	internal:
		DM_STATE_STAT	m_StateStat;		// for stand alone mode
		

		void CloneStateStat( DM_STATE_STAT* pDest)
		{
			pin_ptr<DM_STATE_STAT> pStateStat	=	&m_StateStat;
			memcpy( pDest, pStateStat, sizeof(DM_STATE_STAT) );
		}

	public:
		StateStatistics()
		{
			pin_ptr<DM_STATE_STAT> pStateStat	=	&m_StateStat;
			memset(pStateStat, 0, sizeof(DM_STATE_STAT) );
		}
		

		property StateValue ^ Value
		{
			StateValue ^ get()
			{
				StateValue ^	val = gcnew StateValue();
				val->Set(this);
				return val;
			}

			void set(StateValue ^ value)
			{

				pin_ptr<DM_STATE_STAT> pStateStat	=	&m_StateStat;
				DM_STATE_STAT&	refStat	=	*pStateStat;
		
				pin_ptr<DM_STATE_VALUE> ppOtherVal = &value->m_val;
				refStat.Value	= *ppOtherVal;
			}
		}

		


		

		property System::Double Support
		{
			System::Double get()
			{
				return (System::Double)m_StateStat.dblSupport;
			}
			
			void set(System::Double support)
			{
				m_StateStat.dblSupport	=	support;
			}
		}

		

		property System::Double Variance
		{
			System::Double get()
			{
				return (System::Double)m_StateStat.dblVariance;
			}
		

			void set(System::Double variance)
			{
				m_StateStat.dblVariance	=	variance;
			}
		}

		

		property System::Double Probability
		{
			System::Double get()
			{
				return (System::Double)m_StateStat.dblProbability;
			}

			void set(System::Double probability)
			{
				m_StateStat.dblProbability	=	probability;
			}
		}


		

		property System::Double AdjustedProbability
		{
			System::Double get()
			{
				return (System::Double)m_StateStat.dblAdjustedProbability;
			}
		
			void set(System::Double adjustedProbability)
			{
				m_StateStat.dblAdjustedProbability	=	adjustedProbability;
			}
		}


		

		property System::Double ProbabilityVariance
		{
			System::Double get()
			{
				return (System::Double)m_StateStat.dblProbabilityVariance;
			}

			void set(System::Double probabilityVariance)
			{
				m_StateStat.dblProbabilityVariance =	probabilityVariance;
			}
		}

		property MiningValueType ValueType
		{
			MiningValueType get()
			{
				return (MiningValueType)m_StateStat.lValueType;
			}
			
			void set(MiningValueType valueType)
			{
				m_StateStat.lValueType	=	(LONG)valueType;
			}
		}

	};



	
	public   ref class AttributeStatistics sealed
	{
		StateStatisticsCollection ^	m_pStatesColl;
		

		~AttributeStatistics();
		
	internal:
		
		// for stand-alone mode
		DM_ATTRIBUTE_STAT		m_attStat;		

		System::Collections::ArrayList ^	m_mrgStateStats;

		System::String^						m_mstrNodeID;

		DM_ATTRIBUTE_FLAGS					m_dmaf;

		

		
		StateStatistics^  GetStateStatistics(System::UInt32 nIndex )
		{
			if( nIndex >= (System::UInt32)m_mrgStateStats->Count )
			{
				throw gcnew System::IndexOutOfRangeException();
			}

			Object ^	val	=	m_mrgStateStats[nIndex];
			
			return dynamic_cast<PluginAlgorithms::StateStatistics ^>(val);
		}

		System::UInt32	GetStateStatisticsCount()
		{
			return m_mrgStateStats->Count;
		}

		void	Add(StateStatistics^ stateStatistics)
		{
			m_mrgStateStats->Add( (stateStatistics) );
		}

		void ClearStatistics()
		{
			m_mrgStateStats->Clear();
		}

	private:

	public :
		AttributeStatistics()
		{
			m_pStatesColl	=	nullptr;

			pin_ptr<DM_ATTRIBUTE_STAT> pAttStat	=	&m_attStat;
			memset(pAttStat, 0, sizeof(DM_ATTRIBUTE_STAT));

			m_dmaf		=	0;
			m_mrgStateStats	=	gcnew System::Collections::ArrayList();
		}


		
		

		property StateStatisticsCollection ^	StateStatistics
		{
			StateStatisticsCollection^ get();
		}

		

		property System::UInt32 Attribute
		{
			System::UInt32 get()
			{
				return m_attStat.Attribute;
			}
		

			void set(System::UInt32 att)
			{
				m_attStat.Attribute = att;
			}
		}

		

		property System::String ^  NodeId
		{
			void set(System::String ^);
			System::String^ get();
		}
		
		property System::Double Min
		{
			System::Double get()
			{
				return m_attStat.dblMin;
			}
			void set( System::Double min)
			{
				m_attStat.dblMin	=	min;
			}
		}
		
		


		property System::Double Max
		{
			System::Double get()
			{
				return m_attStat.dblMax;
			}
		
			void set( System::Double max)
			{
				m_attStat.dblMax	=	max;
			}
		}


		

		property System::Double Support
		{
			System::Double get()
			{
				return m_attStat.dblExistingSupport;
			}

			void set( System::Double support)
			{
				m_attStat.dblExistingSupport	=	support;
			}
		}

		

		property System::Double Probability
		{
			System::Double get()
			{
				return m_attStat.dblExistingProbability;
			}
		
			void set( System::Double probability)
			{
				m_attStat.dblExistingProbability	=	probability;
			}
		}


		

		property System::Double AdjustedProbability
		{
			System::Double get()
			{
				return m_attStat.dblExistingAdjustedProbability;
			}
		
			void set(System::Double	adjustedProbability)
			{
				m_attStat.dblExistingAdjustedProbability	=	adjustedProbability;
			}
		}

	};


    [DefaultMember("Item")]
    public   ref class StateStatisticsCollection sealed  : public ICollection

    {
	private:
		AttributeStatistics ^				m_attrStats;
    internal:
		StateStatisticsCollection			()
        {
            m_attrStats =	nullptr;
        }

	    ~StateStatisticsCollection			( void )	
        { 
			m_attrStats = nullptr; 
        }


		void SetAttributeStatistics(AttributeStatistics ^				attrStats)
		{
			m_attrStats = attrStats;
		}

	public:
		void	Add(StateStatistics^ stateStatistics)
		{
			return m_attrStats->Add(stateStatistics);
		}

		

		[System::Diagnostics::CodeAnalysis::SuppressMessage("Microsoft.Design", "CA1043:UseIntegralOrStringArgumentForIndexers")]
		property	StateStatistics^ default[System::UInt32]
		{
			StateStatistics^ get( System::UInt32 index )			
			{ 
				return m_attrStats->GetStateStatistics( index );
			}
		}

        

		property	int    Count
		{
			virtual int             get()
			{
				return m_attrStats->GetStateStatisticsCount();
			}
		}

        

		property	bool    IsSynchronized
		{
			virtual bool    get()
			{
				return false;
			}
		}

        

		property	Object ^    SyncRoot
		{
			virtual Object ^    get()
			{
				return nullptr;
			}
		}

        virtual IEnumerator^              GetEnumerator()
        {
			throw gcnew System::NotSupportedException();
			return nullptr;
        }

        virtual void                        CopyTo(Array ^ array, int index )
        {
			throw gcnew System::NotSupportedException();
        }

    }; // StateStatisticsCollection

    public   ref class MarginalStats sealed 
    {
    private:
        IDMMarginalStat*    m_wpMarginalStat;
		IDMAttributeSet*	m_wpAttrSet;
    internal:
        MarginalStats(IDMMarginalStat*   in_pMarginalStat, IDMAttributeSet* in_pAttrSet)
        {
            m_wpMarginalStat	=	in_pMarginalStat;
			m_wpAttrSet			=	in_pAttrSet;
        }
    public:
        
		System::UInt32      GetTotalCasesCount();
		System::UInt32      GetCasesCount(System::UInt32 attribute, System::UInt32 stateIndex);
		AttributeStatistics ^	GetAttributeStats(System::UInt32 attribute);
		System::Double		GetCaseDensity();
	};
}
}
}
}
        
#pragma warning( pop )
